home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / src / java / net / urlcon~2.jav < prev    next >
Encoding:
Text File  |  1996-01-12  |  19.2 KB  |  574 lines

  1. /*
  2.  * @(#)URLConnection.java    1.18 95/12/18
  3.  * 
  4.  * Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.net;
  21.  
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.util.Hashtable;
  26. import java.util.Date;
  27.  
  28. /**
  29.  * A class to represent an active connection to an object
  30.  * represented by a URL. It is an abstract class that must be
  31.  * subclassed to implement a connection.
  32.  *
  33.  * @version     1.18, 12/18/95
  34.  * @author  James Gosling
  35.  */
  36. abstract public class URLConnection {
  37.     protected URL url;
  38.  
  39.     protected boolean doInput = true;
  40.     protected boolean doOutput = false;
  41.     private static boolean defaultAllowUserInteraction = false;
  42.     protected boolean allowUserInteraction = defaultAllowUserInteraction;
  43.     private static boolean defaultUseCaches = true;
  44.     protected boolean useCaches = defaultUseCaches;
  45.     protected long ifModifiedSince = 0;
  46.  
  47.     protected boolean connected = false;
  48.  
  49.     /**
  50.      * URLConnection objects go through two phases: first they are
  51.      * created, then they are connected.  After being created, and
  52.      * before being connected, various options can be specified
  53.      * (eg. doInput, UseCaches, ...).  After connecting, it is an
  54.      * Error to try to set them.  Operations that depend on being
  55.      * connected, like getContentLength, will implicitly perform the
  56.      * connection if necessary.  Connecting when already connected
  57.      * does nothing.
  58.      */
  59.     abstract public void connect() throws IOException;
  60.  
  61.  
  62.     /**
  63.      * Constructs a URL connection to the specified URL.
  64.      * @param url the specified URL
  65.      */
  66.     protected URLConnection (URL url) {
  67.     this.url = url;
  68.     }
  69.  
  70.     /**
  71.      * Gets the URL for this connection.
  72.      */
  73.     public URL getURL() {
  74.     return url;
  75.     }
  76.  
  77.     /**
  78.      * Gets the content length. Returns -1 if not known.
  79.      */
  80.     public int getContentLength() {
  81.     return getHeaderFieldInt("content-length", -1);
  82.     }
  83.  
  84.     /**
  85.      * Gets the content type. Returns null if not known.
  86.      */
  87.     public String getContentType() {
  88.     return getHeaderField("content-type");
  89.     }
  90.  
  91.     /**
  92.      * Gets the content encoding. Returns null if not known.
  93.      */
  94.     public String getContentEncoding() {
  95.     return getHeaderField("content-encoding");
  96.     }
  97.  
  98.     /**
  99.      * Gets the expriation date of the object. Returns 0 if not known.
  100.      */
  101.     public long getExpiration() {
  102.     return getHeaderFieldDate("expires", 0);
  103.     }
  104.  
  105.     /**
  106.      * Gets the sending date of the object. Returns 0 if not known.
  107.      */
  108.     public long getDate() {
  109.     return getHeaderFieldDate("date", 0);
  110.     }
  111.  
  112.     /**
  113.      * Gets the last modified date of the object. Returns 0 if not known.
  114.      */
  115.     public long getLastModified() {
  116.     return getHeaderFieldDate("last-modified", 0);
  117.     }
  118.  
  119.     /**
  120.      * Gets a header field by name. Returns null if not known.
  121.      * @param name the name of the header field
  122.      */
  123.     public String getHeaderField(String name) {
  124.     return null;
  125.     }
  126.  
  127.     /**
  128.      * Gets a header field by name. Returns null if not known.
  129.      * The field is parsed as an integer.  This form of
  130.      * getHeaderField exists because some connection types
  131.      * (e.g. http-ng) have pre-parsed headers and  this allows them
  132.      * to override this method and short-circuit the parsing.
  133.      * @param name the name of the header field
  134.      * @param Default the value to return if the field is missing
  135.      *    or malformed.
  136.      */
  137.     public int getHeaderFieldInt(String name, int Default) {
  138.     try {
  139.         return Integer.parseInt(getHeaderField(name));
  140.     } catch(Throwable t) {}
  141.     return Default;
  142.     }
  143.  
  144.     /**
  145.      * Gets a header field by name. Returns null if not known.
  146.      * The field will be parsed as a date.  This form of
  147.      * getHeaderField exists because some connection types
  148.      * (eg. http-ng) have pre-parsed headers. This allows them
  149.      * to override this method and short-circuit the parsing.
  150.      * @param name the name of the header field
  151.      * @param Default the value to return if the field is missing
  152.      *    or malformed.
  153.      */
  154.     public long getHeaderFieldDate(String name, long Default) {
  155.     try {
  156.         return Date.parse(getHeaderField(name));
  157.     } catch(Throwable t) {}
  158.     return Default;
  159.     }
  160.  
  161.     /**
  162.      * Returns the key for the nth header field. Returns null if
  163.      * there are fewer than n fields.  This can be used to iterate
  164.      * through all the headers in the message.
  165.      */
  166.     public String getHeaderFieldKey(int n) {
  167.     return null;
  168.     }
  169.  
  170.     /**
  171.      * Returns the value for the nth header field. Returns null if
  172.      * there are fewer than n fields.  This can be used in conjunction
  173.      * with getHeaderFieldKey to iterate through all the headers in the message.
  174.      */
  175.     public String getHeaderField(int n) {
  176.     return null;
  177.     }
  178.  
  179.     /**
  180.      * Gets the object referred to by this URL.  For example, if it
  181.      * refers to an image the object will be some subclass of
  182.      * Image.  The instanceof operator should be used to determine
  183.      * what kind of object was returned.
  184.      * @return    the object that was fetched.
  185.      * @exception UnknownServiceException If the protocol does not
  186.      * support content.
  187.      */
  188.     public Object getContent() throws IOException {
  189.     return getContentHandler().getContent(this);
  190.     }
  191.  
  192.     /**
  193.      * Calls this routine to get an InputStream that reads from the object.
  194.      * Protocol implementors should use this if appropriate.
  195.      * @exception UnknownServiceException If the protocol does not
  196.      * support input.
  197.      */
  198.     public InputStream getInputStream() throws IOException {
  199.     throw new UnknownServiceException("protocol doesn't support input");
  200.     }
  201.  
  202.     /**
  203.      * Calls this routine to get an OutputStream that writes to the object.
  204.      * Protocol implementors should use this if appropriate.
  205.      * @exception UnknownServiceException If the protocol does not
  206.      * support output.
  207.      */
  208.     public OutputStream getOutputStream() throws IOException {
  209.     throw new UnknownServiceException("protocol doesn't support output");
  210.     }
  211.  
  212.     /**
  213.      * Returns the String representation of the URL connection.
  214.      */
  215.     public String toString() {
  216.     return this.getClass().getName() + ":" + url;
  217.     }
  218.  
  219.  
  220.     /** A URL connection can be used for input and/or output.  Set the DoInput
  221.         flag to true if you intend to use the URL connection for input,
  222.         false if not.  The default is true unless DoOutput is explicitly
  223.         set to true, in which case DoInput defaults to false.  */
  224.     public void setDoInput(boolean doinput) {
  225.     if (connected)
  226.         throw new IllegalAccessError("Already connected");
  227.     doInput = doinput;
  228.     }
  229.     public boolean getDoInput() {
  230.     return doInput;
  231.     }
  232.  
  233.     /** A URL connection can be used for input and/or output.  Set the DoOutput
  234.         flag to true if you intend to use the URL connection for output,
  235.         false if not.  The default is false. */
  236.     public void setDoOutput(boolean dooutput) {
  237.     if (connected)
  238.         throw new IllegalAccessError("Already connected");
  239.     doOutput = dooutput;
  240.     }
  241.     public boolean getDoOutput() {
  242.     return doOutput;
  243.     }
  244.  
  245.     /** Some URL connections occasionally need to to interactions with the
  246.         user.  For example, the http protocol may need to pop up an authentication
  247.         dialog.  But this is only appropriate if the application is running
  248.         in a context where there <i>is</i> a user.  The allowUserInteraction
  249.         flag allows these interactions when true.  When it is false, they are
  250.         not allowed and an exception is tossed. The default value can be
  251.         set/gotten using setDefaultAllowUserInteraction, which defaults to false. */
  252.     public void setAllowUserInteraction(boolean allowuserinteraction) {
  253.     if (connected)
  254.         throw new IllegalAccessError("Already connected");
  255.     allowUserInteraction = allowuserinteraction;
  256.     }
  257.     public boolean getAllowUserInteraction() {
  258.     return allowUserInteraction;
  259.     }
  260.  
  261.     /** Sets/gets the default value of the allowUserInteraction flag.  This default
  262.         is "sticky", being a part of the static state of all URLConnections.  This
  263.         flag applies to the next, and all following URLConnections that are created. */
  264.     public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
  265.     defaultAllowUserInteraction = defaultallowuserinteraction;
  266.     }
  267.     public static boolean getDefaultAllowUserInteraction() {
  268.     return defaultAllowUserInteraction;
  269.     }
  270.  
  271.     /** Some protocols do caching of documents.  Occasionally, it is important to be
  272.         able to "tunnel through" and ignore the caches (e.g. the "reload" button in
  273.         a browser).  If the UseCaches flag on a connection is true, the connection is
  274.         allowed to use whatever caches it can.  If false, caches are to be ignored.
  275.         The default value comes from DefaultUseCaches, which defaults to true. */
  276.     public void setUseCaches(boolean usecaches) {
  277.     if (connected)
  278.         throw new IllegalAccessError("Already connected");
  279.     useCaches = usecaches;
  280.     }
  281.     public boolean getUseCaches() {
  282.     return useCaches;
  283.     }
  284.  
  285.     /** Some protocols support skipping fetching unless the object is newer than some amount of time.
  286.     The ifModifiedSince field may be set/gotten to define this time. */
  287.     public void setIfModifiedSince(long ifmodifiedsince) {
  288.     if (connected)
  289.         throw new IllegalAccessError("Already connected");
  290.     ifModifiedSince = ifmodifiedsince;
  291.     }
  292.     public long getIfModifiedSince() {
  293.     return ifModifiedSince;
  294.     }
  295.  
  296.     /** Sets/gets the default value of the UseCaches flag.  This default
  297.         is "sticky", being a part of the static state of all URLConnections.  This
  298.         flag applies to the next, and all following, URLConnections that are created. */
  299.     public boolean getDefaultUseCaches() {
  300.     return defaultUseCaches;
  301.     }
  302.     public void setDefaultUseCaches(boolean defaultusecaches) {
  303.     defaultUseCaches = defaultusecaches;
  304.     }
  305.  
  306.     /**
  307.      * Sets/gets a general request property.
  308.      * @param key The keyword by which the request is known (eg "accept")
  309.      * @param value The value associated with it.
  310.      */
  311.     public void setRequestProperty(String key, String value) {
  312.     if (connected)
  313.         throw new IllegalAccessError("Already connected");
  314.     }
  315.     public String getRequestProperty(String key) {
  316.     if (connected)
  317.         throw new IllegalAccessError("Already connected");
  318.     return null;
  319.     }
  320.  
  321.     /**
  322.      * Sets/gets the default value of a general request property. When a
  323.      * URLConnection is created, it is initialized with these properties.
  324.      * @param key The keyword by which the request is known (eg "accept")
  325.      * @param value The value associated with it.
  326.      */
  327.     public static void setDefaultRequestProperty(String key, String value) {
  328.     }
  329.     public static String getDefaultRequestProperty(String key) {
  330.     return null;
  331.     }
  332.  
  333.     /**
  334.      * The ContentHandler factory.
  335.      */
  336.     static ContentHandlerFactory factory;
  337.  
  338.     /**
  339.      * Sets the ContentHandler factory.
  340.      * @param fac the desired factory
  341.      * @exception Error If the factory has already been defined.
  342.      */
  343.     public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
  344.     if (factory != null) {
  345.         throw new Error("factory already defined");
  346.     }
  347.     SecurityManager security = System.getSecurityManager();
  348.     if (security != null) {
  349.         security.checkSetFactory();
  350.     }
  351.     factory = fac;
  352.     }
  353.  
  354.     private static Hashtable handlers = new Hashtable();
  355.     private static ContentHandler UnknownContentHandlerP = new UnknownContentHandler();
  356.     private static String content_class_prefix = "sun.net.www.content.";
  357.  
  358.     /**
  359.      * Gets the Content Handler appropriate for this connection.
  360.      * @param connection the connection to use.
  361.      */
  362.     synchronized ContentHandler getContentHandler()
  363.     throws UnknownServiceException
  364.     {
  365.     String contentType = getContentType();
  366.     ContentHandler handler = null;
  367.     if (contentType == null)
  368.         throw new UnknownServiceException("no content-type");
  369.     try {
  370.         handler = (ContentHandler) handlers.get(contentType);
  371.         if (handler != null)
  372.         return handler;
  373.     } catch(Exception e) {
  374.     }
  375.     if (factory != null)
  376.         handler = factory.createContentHandler(contentType);
  377.     if (handler == null) {
  378.         try {
  379.         int i = content_class_prefix.length();
  380.         int j = contentType.length();
  381.         char nm[] = new char[i + j];
  382.         content_class_prefix.getChars(0, i, nm, 0);
  383.         contentType.getChars(0, j, nm, i);
  384.         while (--j >= 0) {
  385.             char c = nm[i];
  386.             if (c == '/')
  387.             nm[i] = '.';
  388.             else if (!('A' <= c && c <= 'Z' ||
  389.                    'a' <= c && c <= 'z' ||
  390.                    '0' <= c && c <= '9'))
  391.             nm[i] = '_';
  392.             i++;
  393.         }
  394.         String name = new String(nm);
  395.         try {
  396.             handler = (ContentHandler) Class.forName(name).newInstance();
  397.         } catch(Exception e) {
  398.             e.printStackTrace();
  399.             handler = UnknownContentHandlerP;
  400.         }
  401.         } catch(Exception e) {
  402.         e.printStackTrace();
  403.         handler = UnknownContentHandlerP;
  404.         }
  405.         handlers.put(contentType, handler);
  406.     }
  407.     return handler;
  408.     }
  409.  
  410.     /**
  411.      * A useful utility routine that tries to guess the content-type
  412.      * of an object based upon its extension.
  413.      */
  414.     protected static String guessContentTypeFromName(String fname) {
  415.     String ext = "";
  416.     int i = fname.lastIndexOf('#');
  417.  
  418.     if (i != -1)
  419.         fname = fname.substring(0, i - 1);
  420.     i = fname.lastIndexOf('.');
  421.     i = Math.max(i, fname.lastIndexOf('/'));
  422.     i = Math.max(i, fname.lastIndexOf('?'));
  423.  
  424.     if (i != -1 && fname.charAt(i) == '.') {
  425.         ext = fname.substring(i).toLowerCase();
  426.     }
  427.     return (String) extension_map.get(ext);
  428.     }
  429.  
  430.     static Hashtable extension_map = new Hashtable();
  431.  
  432.     static {
  433.     setSuffix("", "content/unknown");
  434.     setSuffix(".uu", "application/octet-stream");
  435.     setSuffix(".saveme", "application/octet-stream");
  436.     setSuffix(".dump", "application/octet-stream");
  437.     setSuffix(".hqx", "application/octet-stream");
  438.     setSuffix(".arc", "application/octet-stream");
  439.     setSuffix(".o", "application/octet-stream");
  440.     setSuffix(".a", "application/octet-stream");
  441.     setSuffix(".bin", "application/octet-stream");
  442.     setSuffix(".exe", "application/octet-stream");
  443.     /* Temporary only. */
  444.     setSuffix(".z", "application/octet-stream");
  445.     setSuffix(".gz", "application/octet-stream");
  446.  
  447.     setSuffix(".oda", "application/oda");
  448.     setSuffix(".pdf", "application/pdf");
  449.     setSuffix(".eps", "application/postscript");
  450.     setSuffix(".ai", "application/postscript");
  451.     setSuffix(".ps", "application/postscript");
  452.     setSuffix(".rtf", "application/rtf");
  453.     setSuffix(".dvi", "application/x-dvi");
  454.     setSuffix(".hdf", "application/x-hdf");
  455.     setSuffix(".latex", "application/x-latex");
  456.     setSuffix(".cdf", "application/x-netcdf");
  457.     setSuffix(".nc", "application/x-netcdf");
  458.     setSuffix(".tex", "application/x-tex");
  459.     setSuffix(".texinfo", "application/x-texinfo");
  460.     setSuffix(".texi", "application/x-texinfo");
  461.     setSuffix(".t", "application/x-troff");
  462.     setSuffix(".tr", "application/x-troff");
  463.     setSuffix(".roff", "application/x-troff");
  464.     setSuffix(".man", "application/x-troff-man");
  465.     setSuffix(".me", "application/x-troff-me");
  466.     setSuffix(".ms", "application/x-troff-ms");
  467.     setSuffix(".src", "application/x-wais-source");
  468.     setSuffix(".wsrc", "application/x-wais-source");
  469.     setSuffix(".zip", "application/zip");
  470.     setSuffix(".bcpio", "application/x-bcpio");
  471.     setSuffix(".cpio", "application/x-cpio");
  472.     setSuffix(".gtar", "application/x-gtar");
  473.     setSuffix(".shar", "application/x-shar");
  474.     setSuffix(".sh", "application/x-shar");
  475.     setSuffix(".sv4cpio", "application/x-sv4cpio");
  476.     setSuffix(".sv4crc", "application/x-sv4crc");
  477.     setSuffix(".tar", "application/x-tar");
  478.     setSuffix(".ustar", "application/x-ustar");
  479.     setSuffix(".snd", "audio/basic");
  480.     setSuffix(".au", "audio/basic");
  481.     setSuffix(".aifc", "audio/x-aiff");
  482.     setSuffix(".aif", "audio/x-aiff");
  483.     setSuffix(".aiff", "audio/x-aiff");
  484.     setSuffix(".wav", "audio/x-wav");
  485.     setSuffix(".gif", "image/gif");
  486.     setSuffix(".ief", "image/ief");
  487.     setSuffix(".jfif", "image/jpeg");
  488.     setSuffix(".jfif-tbnl", "image/jpeg");
  489.     setSuffix(".jpe", "image/jpeg");
  490.     setSuffix(".jpg", "image/jpeg");
  491.     setSuffix(".jpeg", "image/jpeg");
  492.     setSuffix(".tif", "image/tiff");
  493.     setSuffix(".tiff", "image/tiff");
  494.     setSuffix(".ras", "image/x-cmu-rast");
  495.     setSuffix(".pnm", "image/x-portable-anymap");
  496.     setSuffix(".pbm", "image/x-portable-bitmap");
  497.     setSuffix(".pgm", "image/x-portable-graymap");
  498.     setSuffix(".ppm", "image/x-portable-pixmap");
  499.     setSuffix(".rgb", "image/x-rgb");
  500.     setSuffix(".xbm", "image/x-xbitmap");
  501.     setSuffix(".xpm", "image/x-xpixmap");
  502.     setSuffix(".xwd", "image/x-xwindowdump");
  503.     setSuffix(".htm", "text/html");
  504.     setSuffix(".html", "text/html");
  505.     setSuffix(".text", "text/plain");
  506.     setSuffix(".c", "text/plain");
  507.     setSuffix(".cc", "text/plain");
  508.     setSuffix(".c++", "text/plain");
  509.     setSuffix(".h", "text/plain");
  510.     setSuffix(".pl", "text/plain");
  511.     setSuffix(".txt", "text/plain");
  512.     setSuffix(".java", "text/plain");
  513.     setSuffix(".rtx", "application/rtf");
  514.     setSuffix(".tsv", "text/tab-separated-values");
  515.     setSuffix(".etx", "text/x-setext");
  516.     setSuffix(".mpg", "video/mpeg");
  517.     setSuffix(".mpe", "video/mpeg");
  518.     setSuffix(".mpeg", "video/mpeg");
  519.     setSuffix(".mov", "video/quicktime");
  520.     setSuffix(".qt", "video/quicktime");
  521.     setSuffix(".avi", "application/x-troff-msvideo");
  522.     setSuffix(".movie", "video/x-sgi-movie");
  523.     setSuffix(".mv", "video/x-sgi-movie");
  524.     setSuffix(".mime", "message/rfc822");
  525.     }
  526.  
  527.     static private void setSuffix(String ext, String ct) {
  528.     extension_map.put(ext, ct);
  529.     }
  530.  
  531.     /**
  532.      * This method is used to check for files that have some type
  533.      * that can be determined by inspection.  The bytes at the beginning
  534.      * of the file are examined loosely.  In an ideal world, this routine
  535.      * would not be needed, but in a world where http servers lie
  536.      * about content-types and extensions are often non-standard,
  537.      * direct inspection of the bytes can make the system more robust.
  538.      * The stream must support marks (e.g. have a BufferedInputStream
  539.      * somewhere).
  540.      */
  541.     static protected String guessContentTypeFromStream(InputStream is) throws IOException
  542.     {
  543.     is.mark(10);
  544.     int c1 = is.read();
  545.     int c2 = is.read();
  546.     int c3 = is.read();
  547.     int c4 = is.read();
  548.     int c5 = is.read();
  549.     int c6 = is.read();
  550.     is.reset();
  551.     if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8')
  552.         return "image/gif";
  553.     if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f')
  554.         return "image/x-bitmap";
  555.     if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && c5 == 'M' && c6 == '2')
  556.         return "image/x-pixmap";
  557.     if (c1 == '<')
  558.         if (c2 == '!'
  559.             || (c6 == '>'
  560.             && (c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
  561.                       c3 == 'e' && c4 == 'a' && c5 == 'd')
  562.               || c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y')))
  563.         return "text/html";
  564.     return null;
  565.     }
  566.  
  567. }
  568.  
  569. class UnknownContentHandler extends ContentHandler {
  570.     public Object getContent(URLConnection uc) throws IOException {
  571.     return uc.getInputStream();
  572.     }
  573. }
  574.